// VCppEFLiteDll.cpp
// compile with: /Ehsc /LD

#include "VCppEFLiteDll.h"
#include "SQLParser.h"
#include <stdexcept>
#include <stdarg.h>
#include <sstream>
#include <math.h>

using namespace std;

namespace EFLite {

	/******************************************************/
	/***********		Helper Functions		***********/
	/******************************************************/
	Types RecoverType(string *name, void* Row, list<CD> *cds)
	{

		list<CD>::iterator iter = cds->begin(); // Starting iterator over the CDs
		list<CD>::iterator end = cds->end(); // End iterator over the CDs

		while(iter != end) // Keep going until we reach the end or get a type
			if(iter->ToString() == *name)
				return iter->GetType();

		return (Types) NULL;
	}
	Cell* RecoverCell(string *name, void* Row, list<CD> *cds)
	{

		Types type = (Types) NULL; // Initialize our searching type to be a non-enum value
		char *liter = (char*)Row; // Change the void* to a char* so we can sum to the position of our Cell*

		list<CD>::iterator iter = cds->begin(); // Starting iterator over the CDs
		list<CD>::iterator end = cds->end(); // End iterator over the CDs

		while(iter != end && type == NULL ) { // Keep going until we reach the end or get a type
			if(iter->ToString() == *name)
				type = iter->GetType();

			liter += GetTypeSize(iter->GetType());
		}

		switch(type) { // Based on the type, we return the correct type of Cell*, or NULL if we did not find the column
		case INT:
			return (Int*) liter;
		case FLOAT:
			return (Float*) liter;
		case VARCHAR:
			return (String*) liter;
		case DATE:
			return (Date*) liter;
		case TIME:
			return (Time*) liter;
		default:
			return NULL;
		}
	}
	size_t GetTypeSize(Types t)
	{

		switch(t) {
		case DATE:
			return sizeof(Date);
		case FLOAT:
			return sizeof(Float);
		case INT:
			return sizeof(Int);
		case TIME:
			return sizeof(Time);
		case VARCHAR:
			return sizeof(String);
		default:
			return NULL;
		}
	}
	size_t sizeOfCD(list<CD> Columns)
	{

		size_t totalSize=0;
		list<CD>::iterator iter = Columns.begin();
		list<CD>::iterator end =Columns.end();
		while(iter != end) {
			totalSize += GetTypeSize(iter->GetType());
			advance(iter,1);
		}
		return totalSize;
	}
	vector<string> split(string value, char delimeter)
	{

		string token;
		vector<string> tokens;
		istringstream iss(value);
		while(getline(iss, token, delimeter))
			tokens.push_back(token);

		return tokens;
	}


	/******************************************************/
	/***********		ColumnDefinition Class	***********/
	/******************************************************/
	CD::ColumnDefinition(const ColumnDefinition& CopyCD)
	{
		Name = CopyCD.GetName();
		Type = CopyCD.GetType();
		Key = CopyCD.GetKey();
	}
	CD::ColumnDefinition(string _Name, Types _Type)
	{
		Name = _Name;
		Type = _Type;
		Key = false;
	}
	CD::ColumnDefinition(string _Name, Types _Type, bool _Key)
	{
		Name = _Name;
		Type = _Type;
		Key = _Key;
	}
	Types CD::GetType() const
	{
		return Type;
	}
	bool CD::GetKey() const
	{
		return Key;
	}
	string CD::GetName() const
	{
		return Name;
	}
	string CD::ToString() const
	{
		return Name;
	}
	void CD::Rename(string n)
	{
		Name = n;
	}


	/******************************************************/
	/***********		Entity Class			***********/
	/******************************************************/
	Entity::Entity(const Entity& CopyEntity)
	{
		Name=CopyEntity.GetName();
		Rows=CopyEntity.Rows;
		Columns=CopyEntity.Columns;
	}
	Entity::Entity(string _Name, list<CD> ColumnDefinitions)
	{
		Name = _Name;
		Columns = ColumnDefinitions;
	}
	Entity::Entity(string _Name, ColumnDefinition _ColumnDefinitions[])
	{
		Name = _Name;
		Columns = list<CD> (_ColumnDefinitions, _ColumnDefinitions + sizeof(_ColumnDefinitions) / sizeof(CD));
	}
	Entity* Entity::Where(Predicate *p)
	{
		Entity *ent = new Entity(Name, Columns);
		list<void*>::iterator iter = Rows.begin();
		list<void*>::iterator end = Rows.end();
		void* Row = &Rows;
		while(iter != end) {
			Row = &iter;
			if(p->Evaluate(Row, &Columns)) {
				ent->InsertByAddr(Row);
			}
			advance(iter,1);
		}
		return ent;
	}
	int Entity::Count(string columnName)	//returns number of rows which have non-null values
	{
		//Find Column of interest
		size_t colOffset=0;
		Types colType;
		list<CD>::iterator iterCD = Columns.begin();	//replaced this with RecoverType() when I realized I still needed colOffest
		list<CD>::iterator endCD = Columns.end();
		while(iterCD!=endCD) {
			if(iterCD->ToString()!=columnName) {
				colOffset += GetTypeSize(iterCD->GetType());
			} else {
				colType = iterCD->GetType();
				break;
			}
			advance(iterCD,1);
		}

		int count=0;
		list<void*>::iterator iter = Rows.begin();
		list<void*>::iterator end = Rows.end();
		//Iterate through each Row on Entity and
		while(iter!=end) {
			switch(colType) {	//switch on type because case is required to access HasValue() and Cell is an abstract class (no casts)
			case DATE:
				if(((Date*)((&iter)+colOffset))->HasValue()) {
					count++;
				}
				break;
			case FLOAT:
				if(((Float*)((&iter)+colOffset))->HasValue()) {
					count++;
				}
				break;
			case INT:
				if(((Int*)((&iter)+colOffset))->HasValue()) {
					count++;
				}
				break;
			case TIME:
				if(((Time*)((&iter)+colOffset))->HasValue()) {
					count++;
				}
				break;
			case VARCHAR:
				if(((String*)((&iter)+colOffset))->HasValue())
					count++;
				break;
			default:
				cout<<"Error in insert function"<<endl;
				return 0;
				break;
			}
			advance(iter,1);
		}
		return count;
	}
	int Entity::Sum(string columnName)
	{
		size_t colOffset=0;
		Types colType;
		list<CD>::iterator iterCD = Columns.begin();
		list<CD>::iterator endCD = Columns.end();
		while(iterCD!=endCD) {
			if(iterCD->ToString()!=columnName) {
				colOffset += GetTypeSize(iterCD->GetType());
			} else {
				colType = iterCD->GetType();
				break;
			}
		}

		double total=0;

		list<void*>::iterator iter = Rows.begin();
		list<void*>::iterator end = Rows.end();
		while(iter!=end) {
			switch(colType) {
			case FLOAT:
				if(((Float*)((&iter)+colOffset))->HasValue()) {
					total+= ((Float*)((&iter)+colOffset))->Value;
				}
				break;
			case INT:
				if(((Int*)((&iter)+colOffset))->HasValue()) {
					total+= ((Int*)((&iter)+colOffset))->Value;
				}
				break;
			default:
				cout<<"Error, Sum only supports Int and Float"<<endl;
				return 0;
				break;
			}
			advance(iter,1);
		}
		return (int)total; //WARNING: possible loss of percision
	}
	void* Entity::Min(string columnName)
	{
		Cell* lowestCell=NULL;
		for each(void* row in Rows) {
			Cell* cell = RecoverCell(&columnName,&row,&Columns);
			if(cell->CompareTo(lowestCell)==-1) {
				lowestCell = cell;
			}
		}
		return (void*)lowestCell;
	}
	void* Entity::Max(string columnName)
	{
		Cell* highestCell=NULL;
		for each(void* row in Rows) {
			Cell* cell = RecoverCell(&columnName,&row,&Columns);
			if(highestCell->CompareTo(cell)==-1) {
				highestCell = cell;
			}
		}
		return (void*)highestCell;
	}
	string Entity::GetName() const
	{
		return Name;
	}
	string Entity::ToMetaString() const
	{
		stringstream s;
		for each(CD col in Columns) {
			s << col.ToString() << ",";
		}
		s << endl;
		return s.str();
	}
	string Entity::ToString() const
	{
		list<CD> cols(Columns);		//create localc copy of cols because ToString() is const and we need to access Columns.begin() and end();
		string retVal = ToMetaString();
		stringstream s;
		s << retVal;
		for each(void* r in Rows) {
			void* readPointer = r;
			list<CD>::iterator iter =cols.begin();
			list<CD>::iterator end =cols.end();
			while(iter != end) {
				switch(iter->GetType()) {
				case DATE:
					s << ((Date*)readPointer)->ToString() << ",";
					readPointer =  ((Date*)(readPointer))+1;
					break;
				case FLOAT:
					s << ((Float*)readPointer)->ToString() << ",";
					readPointer =  ((Float*)(readPointer))+1;
					break;
				case INT:
					s << ((Int*)readPointer)->ToString() << ",";
					readPointer =  ((Int*)(readPointer))+1;
					break;
				case TIME:
					s << ((Time*)readPointer)->ToString() << ",";
					readPointer =  ((Time*)(readPointer))+1;
					break;
				case VARCHAR:
					s << ((String*)readPointer)->ToString() << ",";
					readPointer =  ((String*)(readPointer))+1;
					break;
				default:
					throw new exception("Error during Entity::ToString() operation");
					break;
				}
				advance(iter,1);
			}
			s << endl;
		}
		retVal+=s.str();
		return retVal;
	}
	int Entity::RenameColumn(string o, string n)
	{
		list<CD>::iterator iter = Columns.begin();
		list<CD>::iterator end =Columns.end();
		while(iter != end) {
			if((*iter).ToString()==o) {
				(*iter).Rename(n);
				return 0;	//Successful Rename
			}
			advance(iter,1);
		}
		return 1;			//Failed to find CD with name specified by 'o'
	}
	int Entity::InsertByAddr(void* Record)
	{
		void* readPointer = Record;
		void* newRecordAddr = (void*) operator new (sizeOfCD(Columns));
		void* insertAddr = newRecordAddr;
		list<CD>::iterator iter =Columns.begin();
		list<CD>::iterator end =Columns.end();
		while(iter != end) {
			switch(iter->GetType())
			{
			case DATE:
				*((Date*)insertAddr) = *((Date*)readPointer);
				insertAddr =  ((Date*)(insertAddr))+1;
				readPointer =  ((Date*)(readPointer))+1;
				break;
			case FLOAT:
				*((Float*)insertAddr) = *((Float*)readPointer);
				insertAddr =  ((Float*)(insertAddr))+1;
				readPointer =  ((Float*)(readPointer))+1;
				break;
			case INT:
				*((Int*)insertAddr) = *((Int*)readPointer);
				insertAddr =  ((Int*)(insertAddr))+1;
				readPointer =  ((Int*)(readPointer))+1;
				break;
			case TIME:
				*((Time*)insertAddr) = *((Time*)readPointer);
				insertAddr =  ((Time*)(insertAddr))+1;
				readPointer =  ((Time*)(readPointer))+1;
				break;
			case VARCHAR:
				*((String*)insertAddr) = *((String*)readPointer);
				insertAddr =  ((String*)(insertAddr))+1;
				readPointer =  ((String*)(readPointer))+1;
				break;
			default:
				throw new exception("Error during insert operation");
				return 1;
				break;
			}
			advance(iter,1);
		}
		Rows.push_back(newRecordAddr);
		return 0;	//successful insert
	}
	int Entity::Insert(void* Record, ...)
	{
		va_list argList;
		va_start(argList, Record);

		void* RecordStart = (void*) operator new (sizeOfCD(Columns));
		void* insertPointer = RecordStart;

		list<CD>::iterator iter = Columns.begin();
		switch(iter->GetType()) {
		case DATE:
			*((Date*)RecordStart) = *((Date*)(Record));
			insertPointer =  ((Date*)(insertPointer))+1;
			break;
		case FLOAT:
			*((Float*)RecordStart) = *((Float*)(Record));
			insertPointer =  ((Float*)(insertPointer))+1;
			break;
		case INT:
			*((Int*)RecordStart) = *((Int*)(Record));
			insertPointer =  ((Int*)(insertPointer))+1;
			break;
		case TIME:
			*((Time*)RecordStart) = *((Time*)(Record));
			insertPointer =  ((Time*)(insertPointer))+1;
			break;
		case VARCHAR:
			*((String*)RecordStart) = *((String*)(Record));
			insertPointer =  ((String*)(insertPointer))+1;
			break;
		default:
			cout<<"Error in insert function"<<endl;
			return 1;
			break;
		}
		advance(iter,1);
		list<CD>::iterator end =Columns.end();
		while(iter != end) {
			Date dvar(1,1,1);
			Float fvar(1);
			Int ivar(1);
			Time tvar(1,1,1);
			String svar("1");

			switch(iter->GetType()) {
			case DATE:
				dvar = va_arg(argList,Date);
				*((Date*)insertPointer) = dvar;
				insertPointer =  ((Date*)(insertPointer))+1;
				break;
			case FLOAT:
				fvar = va_arg(argList,Float);
				*((Float*)insertPointer) = fvar;
				insertPointer =  ((Float*)(insertPointer))+1;
				break;
			case INT:
				ivar = va_arg(argList,Int);
				*((Int*)insertPointer) = ivar;
				insertPointer =  ((Int*)(insertPointer))+1;
				break;
			case TIME:
				tvar = va_arg(argList,Time);
				*((Time*)insertPointer) = tvar;
				insertPointer =  ((Time*)(insertPointer))+1;
				break;
			case VARCHAR:
				svar = va_arg(argList,String);
				*((String*)insertPointer) = svar;
				insertPointer =  ((String*)(insertPointer))+1;
				break;
			default:
				cout<<"Error in insert function"<<endl;
				return 1;
				break;
			}
			advance(iter,1);
		}
		return 0;
	}
	int Entity::Remove(Predicate* p)
	{
		list<void*>::iterator iter = Rows.begin();
		list<void*>::iterator end = Rows.end();
		void* Row;
		while(iter != end) {
			Row = *iter;
			if(p->Evaluate(Row, &Columns)) {
				list<void*>::iterator temp = iter;
				advance(temp,1);
				Rows.erase(iter);
				delete Row;	//Free memory
				iter = temp;
				return 0;
			} else {
				advance(iter,1);
			}
		}
		return 1;
	}
	int Entity::Update(Predicate* p, ColumnValuePair val)
	{
		list<void*>::iterator rowIt = Rows.begin();
		list<void*>::iterator end = Rows.end();
		int updateCount = 0;
		while(rowIt != end) {
			if(	p->Evaluate(*rowIt,&Columns) ) {
				void* changeAddr = *rowIt;
				list<ColumnDefinition>::iterator colIter = Columns.begin();
				list<ColumnDefinition>::iterator colEnd = Columns.end();
				bool foundCol = false;
				while(colIter != colEnd){
					switch(colIter->GetType()){
						case DATE:
							if(colIter->GetName() == val.columnName){
								*((Date*)changeAddr) = *((Date*)val.Value);
								foundCol=true;
							}else{
								changeAddr = (Date*)changeAddr + 1;
							}
							break;
						case FLOAT:
							if(colIter->GetName() == val.columnName){
								*((Float*)changeAddr) = *((Float*)val.Value);
								foundCol=true;
							}else{
								changeAddr = (Float*)changeAddr + 1;
							}
							break;
						case INT:
							if(colIter->GetName() == val.columnName){
								*((Int*)changeAddr) = *((Int*)val.Value);
								foundCol=true;
							}else{
								changeAddr = (Int*)changeAddr + 1;
							}
							break;
						case TIME:
							if(colIter->GetName() == val.columnName){
								*((Time*)changeAddr) = *((Time*)val.Value);
								foundCol=true;
							}else{
								changeAddr = (Time*)changeAddr + 1;
							}
							break;
						case VARCHAR:
							if(colIter->GetName() == val.columnName){
								*((String*)changeAddr) = *((String*)val.Value);
								foundCol=true;
							}else{
								changeAddr = (String*)changeAddr + 1;
							}
							break;
						default:
							throw new exception("Error during Update operation");
							return 1;
							break;
					}
					if(foundCol){
						updateCount++;
						break;
					}
					advance(colIter,1);
				}
				if(!foundCol){
					cout<<"Could not find column '"<<val.columnName<< "'."<<endl;
					return 1;
				}
			}
			advance(rowIt,1);
		}
		cout<<"Updated '"<<updateCount<<"' columns."<<endl;
		return 0;
	}
	Entity& Entity::operator+= (Entity _Entity)
	{
		for each(void* row in _Entity.Rows) {
			Entity::InsertByAddr(row);
		}
		return *this;
	}
	bool Entity::operator== (Entity& _Entity)
	{
		return (Entity::GetName() == _Entity.GetName());
	}


	/******************************************************/
	/***********		DBContext Class			***********/
	/******************************************************/
	DBContext::DBContext(string _Name)
	{
		Name = _Name;
	}
	int DBContext::ExecuteReader(string query, Entity *result)
	{
		SQLParser sp = SQLParser(this);
		return sp.Parse(query, result);
	}
	int DBContext::ExecuteNonQuery(string query)
	{
		SQLParser sp = SQLParser(this);
		return sp.Parse(query,NULL);
	}
	string DBContext::ToString() const
	{
		return Name;
	}
	int DBContext::Create(Entity &entity)
	{
		string name = entity.GetName();
		for each(Entity ent in Entities) {
			if( entity == ent) {
				cout<<"Error: Entity by name of '"<<entity.GetName()<<"' already exists."<<endl;
				return 1;
			}
		}
		Entities.push_back(entity);
		return 0;
	}
	int DBContext::Delete(Entity &entity)
	{
		list<Entity>::iterator iter = Entities.begin();
		list<Entity>::iterator end = Entities.end();
		while(iter != end) {
			if((*iter)==entity) {
				list<Entity>::iterator temp = iter;
				advance(temp,1);
				Entities.erase(iter);
				delete &entity;
				iter=temp;
				return 0;	// sucessfully deleted
			}
		}
		return 1; // Entity not found. Nothing Deleted
	}
	int DBContext::ExecuteScalar(string query, Int *result)
	{
		return 1;
	}
	int DBContext::ExecuteScalar(string query, Float *result)
	{
		return 1;
	}
	int DBContext::ExecuteScalar(string query, Date *result)
	{
		return 1;
	}
	int DBContext::ExecuteScalar(string query, Time *result)
	{
		return 1;
	}
	int DBContext::ExecuteScalar(string query, String *result)
	{
		return 1;
	}
	Entity& DBContext::operator[] (string _Name)
	{
		list<Entity>::iterator iter = Entities.begin();
		list<Entity>::iterator end =Entities.end();
		bool found=false;
		while(iter != end) {
			if((*iter).ToString()==_Name) {
				found=true;
				break;
			}
			advance(iter,1);
		}
		if(!found) {
			throw new exception("Entity not found");
		}
		return *iter;
	}
	Entity& DBContext::operator [] (string _Names[])
	{
		//Entity tot; for each(const string s in _Names){ tot+=((*this)[s]); };
		int namesLength =1;
		list<Entity>::iterator iter;
		list<Entity>::iterator end = Entities.end();
		bool found=false;
		for(int i=0; i<namesLength; i++) {
			iter = Entities.begin();
			while(iter != end) {
				if((*iter).ToString()==_Names[i]) {
					found=true;
					break;
				}
				if(found)break;
				advance(iter,1);
			}
		}
		if(!found) { //TODO: implement exception throw
			throw new exception("Entity not found");
		}
		return *iter;
	}


	/******************************************************/
	/***********		Date Class				***********/
	/******************************************************/
	void Date::init(int _year, int _month, int _day)
	{
		if(IsValid(_year,_month,_day)) {
			year = _year;
			month = _month;
			day = _day;
		} else throw new exception("Invalid date format.");
	}
	void Date::init(string _Value)
	{
		if(_Value == "NULL" || _Value == "null") {
			year = 1;
			month = 0;
			day = 0;
		} else {
			vector<string> parts = split(_Value, '/');
			int _year = atoi(parts[0].c_str());
			int _month = atoi(parts[1].c_str());
			int _day = atoi(parts[2].c_str());
			init(_year,_month,_day);
		}
	}
	bool Date::IsValid(int _year, int _month, int _day)
	{

		if(_year < 0 || _month <= 0 || _month > 12)
			return false;

		switch(_month) {
		case 1:  // January
		case 3:  // March
		case 5:  // May
		case 7:  // July
		case 8:  // August
		case 10: // October
		case 12: // December
			if(_day > 0 && _day < 32) return true;
		case 2: // February
			if(_year % 4 == 0 && (_year % 400 == 0 || _year % 100 != 0))
				if(_day >= 1 && _day <= 29) return true;
				else return false;
			else if(_day >=1 && _day <= 28) return true;
			else return false;
		default:
			if(_day > 0 && _day < 31) return true;
		}

		return false;
	}
	int Date::GetYear()
	{
		return year;
	}
	int Date::GetMonth()
	{
		return month;
	}
	int Date::GetDay()
	{
		return day;
	}
	bool Date::HasValue()
	{
		return !(year == 1 && month == 1 && day == 1);    // default null value for Date defined as 0001/1/1
	}
	Types Date::GetTypeId()
	{
		return DATE;
	}
	string Date::ToString()
	{
		stringstream s;
		s << year << "/" << month << "/" << day;
		return s.str();
	}
	int Date::CompareTo(Cell* c)
	{
		if(c->GetTypeId() != GetTypeId())
			throw new exception("Date type mismatch."); // Type mismatch
		Date* d = (Date*)c;
		if(year == d->GetYear())
			if(month == d->GetMonth())
				if(day == d->GetDay())
					return 0;
				else if(day < d->GetDay())
					return -1;
				else if(day > d->GetDay())
					return 1;
				else throw new exception("Date:day comparison failed.");
			else if(month < d->GetMonth())
				return -1;
			else if(month > d->GetMonth())
				return 1;
			else throw new exception("Date:month comparison failed.");
		else if(year < d->GetYear())
			return -1;
		else if(year > d->GetYear())
			return 1;
		else throw new exception("Date:year comparison failed.");
	}

	/******************************************************/
	/***********		Time Class				***********/
	/******************************************************/
	void Time::init(int _hours, int _minutes, int _seconds)
	{
		if(IsValid(_hours,_minutes,_seconds)) {
			hours = _hours;
			minutes = _minutes;
			seconds = _seconds;
		} else
			throw new exception("Invalid Time format.");
	}
	void Time::init(string _Value)
	{
		if(_Value == "NULL" || _Value == "null") {
			hours = 0;
			minutes = 0;
			seconds = 0;
		} else {
			vector<string> parts = split(_Value, ':');
			int _hours = atoi(parts[0].c_str());
			int _minutes = atoi(parts[1].c_str());
			int _seconds = atoi(parts[2].c_str());
			init(_hours,_minutes,_seconds);
		}
	}
	bool Time::IsValid(int hours, int minutes, int seconds)
	{
		if(hours > 60 || hours < 0 || minutes > 60 || minutes < 0 || seconds > 60 || seconds < 0)
			return false;
		return true;
	}
	int Time::GetHours()
	{
		return hours;
	}
	int Time::GetMinutes()
	{
		return minutes;
	}
	int Time::GetSeconds()
	{
		return seconds;
	}
	bool Time::HasValue()
	{
		return (hours == 0 && minutes == 0 && seconds == 0);    // default null value for Time defined as 00:00:00
	}
	Types Time::GetTypeId()
	{
		return TIME;
	}
	string Time::ToString()
	{
		stringstream s;
		s << hours << ":" << minutes << ":" << seconds;
		return s.str();
	}
	int Time::CompareTo(Cell* c)
	{
		if(c->GetTypeId() != GetTypeId())
			throw new exception("Invalid Time Format"); // Type mismatch

		Time* t = (Time*)c;

		if(hours == t->GetHours())
			if(minutes == t->GetMinutes())
				if(seconds == t->GetSeconds())
					return 0;
				else if(seconds < t->GetSeconds())
					return -1;
				else if(seconds > t->GetSeconds())
					return 1;
				else throw new exception("Time:seconds comparison failed.");
			else if(minutes < t->GetMinutes())
				return -1;
			else if(minutes > t->GetMinutes())
				return 1;
			else throw new exception("Time:minutes comparison failed.");
		else if(hours < t->GetHours())
			return -1;
		else if(hours > t->GetHours())
			return 1;
		else throw new exception("Time:hours comparison failed.");
	}

	/******************************************************/
	/***********		String Class			***********/
	/******************************************************/
	bool String::HasValue()
	{
		return (Value.length() == 0);    // Zero-length string has no value IMHO
	}
	Types String::GetTypeId()
	{
		return VARCHAR;
	}
	void String::SetValue(string s)
	{
		if(s.length() < MaxSize)
			Value = s;
		else
			throw new exception("String length exceeds max size limit.");
	}
	string String::ToString()
	{
		return Value;
	}
	int String::CompareTo(Cell* c)
	{
		if(c->GetTypeId() != GetTypeId())
			throw new exception("String type mismatch."); // Type mismatch

		String* s = (String*)c;

		return Value.compare(s->ToString());
	}

	/******************************************************/
	/***********		Int Class				***********/
	/******************************************************/
	bool Int::HasValue()
	{
		return (Value!=NULL);
	}
	Types Int::GetTypeId()
	{
		return INT;
	}
	int Int::CompareTo(Cell* c)
	{
		if(c->GetTypeId() != GetTypeId())
			throw new exception("Int type mismatch."); // Type mismatch

		Int* i = (Int*)c;

		if(Value == i->Value) return 0;
		else if(Value < i->Value) return -1;
		else if(Value < i->Value) return 1;
		else throw new exception("Int comparison failed.");
	}
	string Int::ToString()
	{
		stringstream s;
		s << Value;
		return s.str();
	}

	/******************************************************/
	/***********		Float Class				***********/
	/******************************************************/
	bool Float::HasValue()
	{
		return (Value!=NULL);
	}
	Types Float::GetTypeId()
	{
		return FLOAT;
	}
	int Float::CompareTo(Cell* c)
	{
		if(c->GetTypeId() != GetTypeId())
			throw new exception("Float type mismatch."); // Type mismatch

		Float* f = (Float*)c;

		if(Value == f->Value) return 0;
		else if(Value < f->Value) return -1;
		else if(Value < f->Value) return 1;
		else throw new exception("Float comparison failed.");
	}
	string Float::ToString()
	{
		stringstream s;
		s << Value;
		return s.str();
	}

	/******************************************************/
	/***********		Predicate Overloads		***********/
	/******************************************************/
	BP::BP(string &l, string &r)
	{
		ls = &l;
		rs = &r;
		lc = NULL;
		rc = NULL;
	}
	BP::BP(string &l, Cell *r)
	{
		ls = &l;
		rs = NULL;
		lc = NULL;
		rc = r;
	}
	BP::BP(Cell *l, string r)
	{
		ls = NULL;
		rc = NULL;
		lc = l;
		rs = &r;
	}
	BP::BP(Cell *l, Cell *r)
	{
		ls = NULL;
		rs = NULL;
		lc = l;
		rc = r;
	}
	bool BP::Evaluate(void *Row, list<CD> *cds)
	{
		Cell* lcell, *rcell;

		if(*ls != string("") && *rs != string("") && !lc->HasValue() && !rc->HasValue()) {
			lcell = RecoverCell(ls, Row, cds);
			rcell = RecoverCell(rs, Row, cds);
		} else if(*ls != string("") && *rs == string("") && !lc->HasValue() && rc->HasValue()) {
			lcell = RecoverCell(ls, Row, cds);
			rcell = rc;
		} else if(*ls == string("") && *rs != string("") && lc->HasValue() && !rc->HasValue()) {
			lcell = lc;
			rcell = RecoverCell(rs, Row, cds);
		} else if(*ls == string("") && *rs == string("") && lc->HasValue() && rc->HasValue()) {
			lcell = lc;
			rcell = rc;
		} else	// Throw an exception; the predicate was not correctly initialized
			throw new exception();

		if(lcell == NULL)
			// Throw an exception, the cell wasn't found
			// If this was initialized with the predicate... derp
			throw new exception();

		if(rcell == NULL)
			// Throw an exception, the cell wasn't found
			// If this was initialized with the predicate... derp
			throw new exception();

		return Compare(lcell, rcell);
	}
	bool EQ::Compare(Cell *l, Cell *r)
	{
		if(l->GetTypeId() == r->GetTypeId() && l->HasValue() && r->HasValue())
			return l->CompareTo(r) == 0;
		throw new exception();
	}
	bool NEQ::Compare(Cell *l, Cell *r)
	{
		if(l->GetTypeId() == r->GetTypeId() && l->HasValue() && r->HasValue())
			return l->CompareTo(r) != 0;
		throw new exception();
	}
	bool GT::Compare(Cell *l, Cell *r)
	{
		if(l->GetTypeId() == r->GetTypeId() && l->HasValue() && r->HasValue())
			return l->CompareTo(r) > 0;
		throw new exception();
	}
	bool GTE::Compare(Cell *l, Cell *r)
	{
		if(l->GetTypeId() == r->GetTypeId() && l->HasValue() && r->HasValue())
			return l->CompareTo(r) >= 0;
		throw new exception();
	}
	bool LT::Compare(Cell *l, Cell *r)
	{
		if(l->GetTypeId() == r->GetTypeId() && l->HasValue() && r->HasValue())
			return l->CompareTo(r) < 0;
		throw new exception();
	}
	bool LTE::Compare(Cell *l, Cell *r)
	{
		if(l->GetTypeId() == r->GetTypeId() && l->HasValue() && r->HasValue())
			return l->CompareTo(r) <= 0;
		throw new exception();
	}
	bool AND::Evaluate(void* Row, list<CD> *cds)
	{
		return l->Evaluate(Row, cds) && r->Evaluate(Row, cds);
	}
	bool OR::Evaluate(void* Row, list<CD> *cds)
	{
		return l->Evaluate(Row, cds) || r->Evaluate(Row, cds);
	}
	bool NOT::Evaluate(void* Row, list<CD> *cds)
	{
		return !(p->Evaluate(Row, cds));
	}
}
